Completed
Pull Request — master (#99)
by
unknown
01:08
created

BtccomConverter.getUrlForAddress   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 1
c 3
b 0
f 0
nc 1
dl 0
loc 3
rs 10
nop 1
1
var RestClient = require('./rest_client');
2
var Wallet = require('./wallet');
3
var bitcoinJS = require('bitcoinjs-lib');
4
5
var BtccomConverter = function(network, useNewCashAddr) {
6
    this.network = network;
7
    this.useNewCashAddr = useNewCashAddr;
8
9
    this.specialRawTxClientOnly = new RestClient({
10
        host: "btc.com",
11
        https: true,
12
        port: 443,
13
        endpoint: "/"
14
    });
15
    this.btccomApiClient = new RestClient({
16
        host: "chain.api.btc.com",
17
        https: true,
18
        port: 443,
19
        endpoint: "/v3"
20
    });
21
};
22
23
function getAddressScriptInfo(address, network, useNewCashAddr) {
24
    try {
25
        var addressScriptInfo = bitcoinJS.address.toOutputScript(address, network, useNewCashAddr);
26
    } catch (e) {
27
        addressScriptInfo = null;
28
    }
29
    return addressScriptInfo;
30
}
31
32
function getScriptAsm(chunks) {
33
34
    try {
35
        var scriptAsm = bitcoinJS.script.toASM(chunks);
36
    } catch (e) {
37
        scriptAsm = null;
38
    }
39
    return scriptAsm;
40
}
41
42
function getType(script) {
43
    try {
44
        var type = bitcoinJS.script.classifyOutput(script);
45
    } catch (e) {
46
        type = null;
47
    }
48
    return type;
49
}
50
51
function getBase58AddressHash160(address, network, useNewCashAddr) {
52
    try {
53
        var addressInfo = Wallet.getAddressAndType(address, network, useNewCashAddr);
54
    } catch (e) {
55
        console.log(e);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
56
        return null;
57
    }
58
59
    if (addressInfo.type == "base58") {
60
        return addressInfo.decoded.hash;
61
    } else if (addressInfo.type == "bech32") {
62
        if (addressInfo.data.length == 20) {
63
            return addressInfo.decoded.hash;
64
        }
65
        return null;
66
    } else if (addressInfo.type == "") {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if addressInfo.type == "" is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
67
        return addressInfo.decoded.hash;
68
    }
69
}
70
71
var utcTimestampToISODateStr = function(time) {
72
    new Date
0 ignored issues
show
Unused Code Best Practice introduced by
The object created with new Date() is not used but discarded. Consider invoking another function instead of a constructor if you are doing this purely for side effects.
Loading history...
73
    return (new Date(time)).toISOString();
74
};
75
76
BtccomConverter.prototype.getUrlForBlock = function(blockHash) {
77
    return "/block/" + blockHash;
78
};
79
80
BtccomConverter.prototype.getUrlForTransaction = function(txId) {
81
    return "/tx/" + txId + "?verbose=3"
82
};
83
84
BtccomConverter.prototype.getUrlForBlockTransaction = function(blockHash) {
85
    return "/block/" + blockHash + "/tx"
86
};
87
88
BtccomConverter.prototype.getUrlForAddress = function(address) {
89
    return "/address/" + address;
90
};
91
92
BtccomConverter.prototype.getUrlForAddressTransactions = function(address) {
93
    return "/address/" + address + "/tx?verbose=3";
94
};
95
96
BtccomConverter.prototype.getUrlForAddressUnspent = function(address) {
97
    return "/address/" + address + "/unspent";
98
};
99
100
BtccomConverter.prototype.getUrlForAllblocks = function() {
101
    return "/all-blocks";
102
};
103
104
105
BtccomConverter.prototype.convertBlock = function(oldData) {
106
    var data = {};
107
    data.hash = oldData.data.hash;
108
    data.version = oldData.data.version;
109
    data.height = oldData.data.height;
110
    data.block_time = utcTimestampToISODateStr(oldData.data.timestamp);
111
    data.arrival_time = utcTimestampToISODateStr(oldData.data.timestamp);
112
    data.bits = oldData.data.bits;
113
    data.nonce = oldData.data.nonce;
114
    data.merkleroot = oldData.data.mrkl_root;
115
    data.prev_block = oldData.data.prev_block_hash;
116
    data.next_block = oldData.data.next_block_hash ;
117
    data.byte_size = oldData.data.size;
118
    data.difficulty = oldData.data.pool_difficulty; //todo is there a replacement? kill this off for now
119
    data.transactions = oldData.data.tx_count;
120
    data.reward_block = oldData.data.reward_block;
121
    data.reward_fees = oldData.data.reward_fees;
122
    data.created_at = oldData.data.created_at;
123
    data.confirmations = oldData.data.confirmations;
124
    data.is_orphan = oldData.data.is_orphan ;
125
    data.is_sw_block = oldData.data.is_sw_block;
126
    data.byte_size = oldData.data.stripped_size;
127
    data.weight = oldData.data.weight;
128
    data.miningpool_name = oldData.data.miningpool_name ? oldData.data.miningpool_name : null;
129
    data.miningpool_url  = oldData.data.miningpool_url ?  oldData.data.miningpool_url : null;
130
    data.miningpool_slug = oldData.data.miningpool_slug ? oldData.data.miningpool_slug : null;
131
132
    return data;
133
};
134
135
136
BtccomConverter.prototype.convertBlockTx = function(oldData) {
137
138
    var list = [];
139
    oldData.data.list.forEach(function(j1) {
140
        var j = convertBtccomTxToBlocktrail(j1);
141
142
        list.push(j);
143
    });
144
    return {
145
        data: list,
146
        current_page: oldData.data.page,
147
        per_page: oldData.data.pagesize,
148
        total: oldData.data.total_count
149
    };
150
};
151
152
function convertBtccomTxToBlocktrail(tx) {
153
    var data = {};
154
155
    data.size = tx.vsize;
156
    data.hash = tx.hash;
157
    data.block_height = tx.block_height ;
158
    data.block_time = utcTimestampToISODateStr(tx.block_time)
159
    data.block_hash = 123//todo;
160
    data.confirmations = tx.confirmations;
161
    data.is_coinbase = tx.is_coinbase;
162
163
    var totalInputValue;
164
    if (data.is_coinbase) {
165
        totalInputValue = tx.outputs[0].value - tx.fee
166
    } else {
167
        totalInputValue = tx.inputs_value;
168
    }
169
170
    data.total_input_value = totalInputValue;
171
    data.total_output_value = tx.outputs[0].value;
172
    data.total_fee = tx.fee;
173
    data.contains_dust = null; //todo is there a replacement? kill this off for now
174
    data.inputs = [];
175
    data.outputs = [];
176
    for (var inputIdx in tx.inputs) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
177
        var i = tx.inputs[inputIdx];
178
        var scriptType;
179
        var inputValue;
180
        var inputTxid;
181
        var outpointIdx;
182
183
        if (data.is_coinbase && i.prev_position == -1 && i.prev_tx_hash == "0000000000000000000000000000000000000000000000000000000000000000") {
184
            scriptType = "coinbase";
185
            inputTxid = null; // debatable.
186
            inputValue = totalInputValue;
187
            outpointIdx = 0xffffffff;
0 ignored issues
show
Unused Code introduced by
The variable outpointIdx seems to be never used. Consider removing it.
Loading history...
188
        } else {
189
            scriptType = i.prev_type;
190
            inputValue = i.prev_value;
191
            inputTxid = i.prev_tx_hash;
192
            outpointIdx = i.prev_position
193
        }
194
195
        var prevAddress = null;
196
        if (typeof i.prev_addresses === "Array") {
197
            prevAddress = i.prev_addresses;
198
        }
199
200
        data.inputs.push({
201
            output_hash: inputTxid,
202
            output_index: inputIdx,
203
            output_confirmed: false, //todo ask ruben
204
            value: inputValue,
205
            sequence: i.sequence,
206
            address: prevAddress,
207
            type: scriptType,
208
            prev_value: 0,
209
            multisig: i.multisig == undefined ? null : i.multisig,
210
            multisig_addresses: i.multisig_addresses == undefined ? null : i.multisig_addresses,
211
            script_signature: i.script_hex
212
        });
213
    }
214
215
    for (var outIdx in tx.outputs) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
216
        var i = tx.outputs[outIdx];
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable i already seems to be declared on line 177. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
217
        data.outputs.push({
218
            index: outIdx,
219
            value: i.value,
220
            address: i.addresses,
221
            type: convertBtccomOutputScriptType(i.type),
222
            script: i.script_asm,
223
            script_hex: i.script_hex,
224
            spent_hash: i.spent_by_tx,
225
            spent_index: i.spent_by_tx_position
226
        });
227
    }
228
229
    data.size = tx.size;
230
    data.is_double_spend = tx.is_double_spend;
231
    data.opt_in_rbf = false; //todo ask ruben
232
    data.unconfirmed_inputs = true; //todo ask ruben
233
    data.lock_time_timestamp = null;
234
    data.lock_time_block_height = null;
235
236
    /*
237
    Extra fields from Btc.com
238
    */
239
240
    data.is_sw_tx = tx.is_sw_tx;
241
    data.weight = tx.weight;
242
    data.witness_hash = tx.witness_hash;
243
    data.lock_time  = tx.lock_time;
244
    data.sigops = tx.sigops;
245
    data.version = tx.version;
246
247
    return data;
248
}
249
250
BtccomConverter.prototype.convertTx = function(oldData, rawTx) {
251
    var data = convertBtccomTxToBlocktrail(oldData.data);
252
    data.raw = rawTx;
253
    return data;
254
}
255
256
//BtccomConverter.prototype.handleResponse() {
257
258
    // err_no	2
259
    // err_msg	"bad params: bc1qj9hlju59t0m4389033r2x8mlxwc86qgqm9flm626sd22cdhfs9jsyrrp6q"
260
//}
261
262
function convertBtccomOutputScriptType(scriptType) {
263
    switch (scriptType) {
264
        case "P2PKH_PUBKEY":
265
            return "pubkey";
266
        case "P2PKH":
267
            return "pubkeyhash";
268
        case "P2SH":
269
            return "scripthash";
270
        case "P2WSH_V0":
271
            return "witnessscripthash";
272
        case "P2WPKH":
273
            return "witnesspubkeyhash";
274
        default:
275
            throw new Error("Not implemented yet, do this later")
276
    }
277
}
278
/// self.converter.convertAddressTx(self.converter.handleResponse(data))
279
BtccomConverter.prototype.convertAddressTx = function(oldData) {
280
    var data = [];
281
282
283
    oldData.data.list.forEach(function(i) {
284
        var e  = {};
285
        var inputs = [];
286
        var outputs = [];
287
288
        e.hash = i.hash;
289
        e.time = i.block_time;
290
        e.confirmations = i.confirmations;
291
        e.block_height = i.block_height;
292
        e.block_hash = i.hash;
293
        e.is_coinbase = i.is_coinbase;
294
        e.estimated_value = i.estimated_value; //todo ask ruben
295
        e.total_input_value = i.inputs_value;
296
        e.total_output_value = i.outputs_value;
297
        e.total_fee = i.fee;
298
        e.estimated_change = i.estimated_change;
299
        e.estimated_change_address = i.estimated_change_address;
300
301
        for (var j in i.inputs) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
302
            var inIdx = i.inputs[j];
303
            inputs.push({
304
                index: j,
305
                output_hash: inIdx.prev_tx_hash,
306
                output_index: inIdx.sequence,
307
                value: inIdx.prev_value,
308
                address: inIdx.prev_addresses,
309
                type:  e.is_coinbase ? e.is_coinbase : convertBtccomOutputScriptType(inIdx.prev_type),
310
                multisig: inIdx.multisig == undefined ? null : inIdx.multisig,
311
                script_signature: inIdx.script_hex,
312
                script: inIdx.script_asm
313
            });
314
        }
315
316
        for (var j in i.outputs) {
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable j already seems to be declared on line 301. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
317
            var outIdx = i.outputs[j];
318
            outputs.push({
319
                index: j,
320
                value: outIdx.value,
321
                address: outIdx.addresses,
322
                type: outIdx.type,
323
                multisig: outIdx.multisig == undefined ? null : outIdx.multisig,
324
                script: outIdx.script_asm,
325
                spent_hash: outIdx.spent_by_tx == undefined ? null : outIdx.spent_by_tx,
326
                script_hex: outIdx.script_hex,
327
                spent_index: outIdx.spent_by_tx_position
328
329
            });
330
        }
331
332
        e.inputs = inputs;
333
        e.outputs  = outputs;
334
335
        /*
336
        Extra fields from Btc.com
337
         */
338
339
        e.is_double_spend = i.is_double_spend;
340
        e.is_sw_tx = i.is_sw_tx;
341
        e.weight = i.weight;
342
        e.witness_hash = i.witness_hash;
343
        e.version = i.version;
344
        data.push(e);
345
    });
346
347
    return {
348
        data: data,
349
        current_page: oldData.data.page,
350
        per_page: oldData.data.pagesize,
351
        total: oldData.data.total_count
352
    };
353
};
354
355
BtccomConverter.prototype.convertAddress = function(oldData, firstSeen) {
356
357
    var data = {};
358
    data.address = oldData.data.address;
359
    data.hash160 = getBase58AddressHash160(oldData.data.address, this.network, this.useNewCashAddr).toString("hex");
360
    data.balance = oldData.data.balance;
361
    data.received = oldData.data.received;
362
    data.sent = oldData.data.sent;
363
    data.transactions = oldData.data.tx_count;
364
    data.utxos = oldData.data.unspent_tx_count - 1;
365
    data.unconfirmed_received = oldData.data.unconfirmed_received;
366
    data.unconfirmed_sent = oldData.data.unconfirmed_sent;
367
    data.unconfirmed_transactions = oldData.data.unconfirmed_tx_count;
368
    data.unconfirmed_utxos = oldData.data.unspent_tx_count;
369
    data.first_tx = oldData.data.first_tx;
370
    data.last_tx = oldData.data.last_tx;
371
    data.category = null; //todo is there a replacement? kill this off for now
372
    data.tag = null; //todo is there a replacement? kill this off for now
373
    data.first_seen = firstSeen;
374
    data.last_seen = firstSeen;
375
376
    return {
377
        data: data
378
    };
379
380
}
381
382
BtccomConverter.prototype.convertAddressUnspentOutputs = function(oldData, address) {
383
384
    var data = [];
385
    var script = getAddressScriptInfo(address, this.network, this.useNewCashAddr);
386
    var script_hex = script.toString("hex");
387
    var script_asm = getScriptAsm(script);
388
    var type = getType(script);
389
    oldData.data.list.forEach(function(i) {
390
        data.push({
391
            hash: i.tx_hash,
392
            time: undefined, //todo
393
            confirmations: i.confirmations,
394
            is_coinbase: true, //todo ask Ruben
395
            value: i.value,
396
            index: i.tx_output_n,
397
            address: address,
398
            type: type,
399
            multisig: null,
400
            script: script_asm,
401
            script_hex: script_hex
402
        })
403
404
    });
405
406
    return {
407
        data: data,
408
        current_page: oldData.data.page,
409
        total: oldData.data.total_count
410
    }
411
}
412
413
exports = module.exports = BtccomConverter;
414